package com.fsbm.ctech.maxis.ebpsbackend;

import java.sql.*;
import java.io.*;
import java.util.*;

import oracle.sql.*;
import oracle.jdbc.*;



public class GetZipBlob  {

	private static ConfigObject cfgObj = new ConfigObject();

	private String instanceID = null;

    private String          inputBinaryFileName     = null;
    private File            inputBinaryFile         = null;

    private String          outputBinaryFileName1   = null;
    private File            outputBinaryFile1       = null;

    private String          outputBinaryFileName2   = null;
    private File            outputBinaryFile2       = null;

	private static String   dbUser = cfgObj.zipAndLoad_DB_User;
	private static String   dbPassword = cfgObj.zipAndLoad_DB_Password;
    private Connection      conn                    = null;


    /**
     * Default constructor used to create this object. Responsible for setting
     * this object's creation date, as well as incrementing the number instances
     * of this object.
     * @param args Array of string arguments passed in from the command-line.
     * @throws java.io.IOException
     */
    public GetZipBlob(String[] args) throws IOException {

		instanceID = args[0];

        outputBinaryFileName1 = instanceID + ".getBytes.zip";
        outputBinaryFileName2 = instanceID + ".Streams.zip";

    }


    /**
     * Obtain a connection to the Oracle database.
     * @throws java.sql.SQLException
     */
    public void openOracleConnection()
            throws    SQLException
                    , IllegalAccessException
                    , InstantiationException
                    , ClassNotFoundException {

        String driver_class  = "oracle.jdbc.driver.OracleDriver";
        String connectionURL = null;

        try {
            Class.forName (driver_class).newInstance();
            connectionURL =  cfgObj.zipAndLoad_DB_URL;
            conn = DriverManager.getConnection(connectionURL, dbUser, dbPassword);
            conn.setAutoCommit(false);
            System.out.println("Connected.\n");
        } catch (IllegalAccessException e) {
            System.out.println("Illegal Access Exception: (Open Connection).");
            e.printStackTrace();
            throw e;
        } catch (InstantiationException e) {
            System.out.println("Instantiation Exception: (Open Connection).");
            e.printStackTrace();
            throw e;
        } catch (ClassNotFoundException e) {
            System.out.println("Class Not Found Exception: (Open Connection).");
            e.printStackTrace();
            throw e;
        } catch (SQLException e) {
            System.out.println("Caught SQL Exception: (Open Connection).");
            e.printStackTrace();
            throw e;
        }

    }


    /**
     * Close Oracle database connection.
     * @throws java.sql.SQLException
     */
    public void closeOracleConnection() throws SQLException {

        try {
            conn.close();
            System.out.println("Disconnected.\n");
        } catch (SQLException e) {
            System.out.println("Caught SQL Exception: (Closing Connection).");
            e.printStackTrace();
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException e2) {
                    System.out.println("Caught SQL (Rollback Failed) Exception.");
                    e2.printStackTrace();
                }
            }
            throw e;
        }

    }


    /**
     * Method used to print program usage to the console.
     */
    static public void usage() {
        System.out.println("\nUsage: java GetZipBlob \"Instance ID\"\n");
    }


    /**
     * Validate command-line arguments to this program.
     * @param args Array of string arguments passed in from the command-line.
     * @return Boolean - value of true if correct arguments, false otherwise.
     */
    static public boolean checkArguments(String[] args) {

        if (args.length == 1) {
            return true;
        } else {
            return false;
        }

    }


    /**
     * Override the Object toString method. Used to print a version of this
     * object to the console.
     * @return String - String to be returned by this object.
     */
    public String toString() {

        String retValue;

        retValue  = "Input File         : " + inputBinaryFileName    + "\n" +
                    "Output File (1)    : " + outputBinaryFileName1  + "\n" +
                    "Output File (2)    : " + outputBinaryFileName2  + "\n" +
                    "Database User      : " + dbUser;
        return retValue;

    }

    /**
     * Method used to write the contents (data) from an Oracle BLOB column to
     * an O/S file. This method uses one of two ways to get data from the BLOB
     * column - namely the getBytes() method. The other way to read data from an
     * Oracle BLOB column is to use Streams.
     *
     * @throws java.io.IOException
     * @throws java.sql.SQLException
     */
    public void readBLOBToFileGet()
            throws IOException, SQLException {

        FileOutputStream    outputFileOutputStream      = null;
        String              sqlText                     = null;
        Statement           stmt                        = null;
        ResultSet           rset                        = null;
        BLOB                image                       = null;
        long                blobLength;
        long                position;
        int                 chunkSize;
        byte[]              binaryBuffer;
        int                 bytesRead                   = 0;
        int                 bytesWritten                = 0;
        int                 totbytesRead                = 0;
        int                 totbytesWritten             = 0;

        try {

            stmt = conn.createStatement();

            outputBinaryFile1       = new File(outputBinaryFileName1);
            outputFileOutputStream  = new FileOutputStream(outputBinaryFile1);

            sqlText =
                "SELECT zipBLOB " +
                "FROM   statementext " +
                "WHERE  instanceID = " + instanceID + " " +
                "FOR UPDATE";
            rset = stmt.executeQuery(sqlText);
            rset.next();
            image = ((OracleResultSet) rset).getBLOB("zipBLOB");

            blobLength = image.length();
            chunkSize = image.getChunkSize();
            binaryBuffer = new byte[chunkSize];

            for (position = 1; position <= blobLength; position += chunkSize) {

                // Loop through while reading a chunk of data from the BLOB
                // column using the getBytes() method. This data will be stored
                // in a temporary buffer that will be written to disk.
                bytesRead = image.getBytes(position, chunkSize, binaryBuffer);

                // Now write the buffer to disk.
                outputFileOutputStream.write(binaryBuffer, 0, bytesRead);

                totbytesRead += bytesRead;
                totbytesWritten += bytesRead;

            }

            outputFileOutputStream.close();

            conn.commit();
            rset.close();
            stmt.close();

            System.out.println(
                "==========================================================\n" +
                "  GET METHOD\n" +
                "==========================================================\n" +
                "Wrote BLOB column data to file " + outputBinaryFile1.getName() + ".\n" +
                totbytesRead + " bytes read.\n" +
                totbytesWritten + " bytes written.\n"
            );

        } catch (IOException e) {
            System.out.println("Caught I/O Exception: (Write BLOB value to file - Get Method).");
            e.printStackTrace();
            throw e;
        } catch (SQLException e) {
            System.out.println("Caught SQL Exception: (Write BLOB value to file - Get Method).");
            System.out.println("SQL:\n" + sqlText);
            e.printStackTrace();
            throw e;
        }

    }


    /**
     * Method used to write the contents (data) from an Oracle BLOB column to
     * an O/S file. This method uses one of two ways to get data from the BLOB
     * column - namely using Streams. The other way to read data from an
     * Oracle BLOB column is to use getBytes() method.
     *
     * @throws java.io.IOException
     * @throws java.sql.SQLException
     */
    public void readBLOBToFileStream()
            throws IOException, SQLException {

        FileOutputStream    outputFileOutputStream      = null;
        InputStream         blobInputStream             = null;
        String              sqlText                     = null;
        Statement           stmt                        = null;
        ResultSet           rset                        = null;
        BLOB                image                       = null;
        int                 chunkSize;
        byte[]              binaryBuffer;
        int                 bytesRead                   = 0;
        int                 bytesWritten                = 0;
        int                 totBytesRead                = 0;
        int                 totBytesWritten             = 0;

        try {

            stmt = conn.createStatement();

            outputBinaryFile2       = new File(outputBinaryFileName2);
            outputFileOutputStream  = new FileOutputStream(outputBinaryFile2);

            sqlText =
                "SELECT zipBLOB " +
                "FROM   statementext " +
                "WHERE  instanceID = " + instanceID + " " +
                "FOR UPDATE";
            rset = stmt.executeQuery(sqlText);
            rset.next();
            image = ((OracleResultSet) rset).getBLOB("zipBLOB");

            // Will use a Java InputStream object to read data from a BLOB (can
            // also be used for a CLOB) object. In this example, we will use an
            // InputStream to read data from a BLOB.
            blobInputStream = image.getBinaryStream();

            chunkSize = image.getChunkSize();
            binaryBuffer = new byte[chunkSize];

            while ((bytesRead = blobInputStream.read(binaryBuffer)) != -1) {

                // Loop through while reading a chunk of data from the BLOB
                // column using an InputStream. This data will be stored
                // in a temporary buffer that will be written to disk.
                outputFileOutputStream.write(binaryBuffer, 0, bytesRead);

                totBytesRead += bytesRead;
                totBytesWritten += bytesRead;

            }

            outputFileOutputStream.close();
            blobInputStream.close();

            conn.commit();
            rset.close();
            stmt.close();

            System.out.println(
                "==========================================================\n" +
                "  INPUT STREAMS METHOD\n" +
                "==========================================================\n" +
                "Wrote BLOB column data to file " + outputBinaryFile2.getName() + ".\n" +
                totBytesRead + " bytes read.\n" +
                totBytesWritten + " bytes written.\n"
            );

        } catch (IOException e) {
            System.out.println("Caught I/O Exception: (Write BLOB value to file - Streams Method).");
            e.printStackTrace();
            throw e;
        } catch (SQLException e) {
            System.out.println("Caught SQL Exception: (Write BLOB value to file - Streams Method).");
            System.out.println("SQL:\n" + sqlText);
            e.printStackTrace();
            throw e;
        }

    }


    /**
     * Sole entry point to the class and application.
     * @param args Array of string arguments passed in from the command-line.
     */
    public static void main(String[] args) {

        GetZipBlob getZipBlob = null;

        if (checkArguments(args)) {

            try {

                getZipBlob = new GetZipBlob(args);

                System.out.println("\n" + getZipBlob + "\n");

                getZipBlob.openOracleConnection();

                getZipBlob.readBLOBToFileGet();

                getZipBlob.readBLOBToFileStream();

                getZipBlob.closeOracleConnection();

            } catch (IllegalAccessException e) {
                System.out.println("Caught Illegal Accecss Exception. Exiting.");
                e.printStackTrace();
                System.exit(1);
            } catch (InstantiationException e) {
                System.out.println("Instantiation Exception. Exiting.");
                e.printStackTrace();
                System.exit(1);
            } catch (ClassNotFoundException e) {
                System.out.println("Class Not Found Exception. Exiting.");
                e.printStackTrace();
                System.exit(1);
            } catch (SQLException e) {
                System.out.println("Caught SQL Exception. Exiting.");
                e.printStackTrace();
                System.exit(1);
            } catch (IOException e) {
                System.out.println("Caught I/O Exception. Exiting.");
                e.printStackTrace();
                System.exit(1);
            }

        } else {
            System.out.println("\nERROR: Invalid arguments.");
            usage();
            System.exit(1);
        }

        System.exit(0);
    }

}

